#ifndef _SHARP_DYNAMICARRAY_H
#define _SHARP_DYNAMICARRAY_H

#include "sharp-common.h"

/**
 * @file src/dynamicarray.c
 */

typedef struct sharp_dynamicarray_s sharp_dynamicarray;

/**
 * Defines a dynamic array. Dynamic arrays are essentially arrays that grow as
 * required once they hit their size cap. Remember to call 
 * sharp_dynamicarray_init() before using one. Dynamic arrays grow by a factor
 * of two every time their maximum size is hit.
 *
 * All members of the array must be of the same type (actually, they only need
 * to have the same size, but that's fairly unlikely for different types).
 */
struct sharp_dynamicarray_s {
    /** Pointer to data array */
    void *data;
    /** The current number of elements in this array */
    int length;
    /** The maximum number of elements before this array must be reallocated */
    int size;
    /** The size of an individual member of the array */
    size_t membersize;
};

/**
 * Initialize a dynamically allocated array.
 * @param list pointer to the pointer to a list
 * @param membersize the size any single member of the list has
 * @return false if the memory allocation fails, true otherwise
 *
 * Empty lists will have 0 elements and an initial size of 2.
 */
bool sharp_dynamicarray_init(sharp_dynamicarray **list, size_t membersize);

/**
 * Append an element to an array.
 * @param list the list to add the element to
 * @param data the data to add
 * @return false if the memory allocation fails, true otherwise
 *
 * Note that you should not try to pass NULL as the list argument; however,
 * NULL is a valid value for the data parameter.
 */
bool sharp_dynamicarray_append(sharp_dynamicarray **list, void **data);

/**
 * Delete the last element of the given dynamic array.
 * @param list the list to remove the element from
 * @param data a pointer to hold the data that was removed
 * @return true if the element could be removed, false otherwise (in which case
 *         the list had 0 elements)
 *
 * Do not use NULL for either list or data; you will get a NULL pointer
 * dereference.
 */
bool sharp_dynamicarray_delete_last(sharp_dynamicarray **list, void **data);

/**
 * Reallocate the array.
 * @param list the array to reallocate
 * @return false if list was NULL, true otherwise.
 *
 * This function will reallocate the list to the current length. Assume you
 * have an array of 100 elements and delete 80 of them, it may make sense to
 * reallocate the array in order to save space, so you may call this function.
 */
bool sharp_dynamicarray_clean(sharp_dynamicarray **list);

/**
 * Resize the array.
 * @param list the array to resize
 * @param size the size to use
 * @return true if the array was resized, false if it wasn't (i.e., there
 *         wasn't enough memory to reallocate the list)
 *
 * You may want to call this for example after list creation if you already
 * know how many elements your array will have in the end.
 */
bool sharp_dynamicarray_resize(sharp_dynamicarray **list, int size);

/**
 * Delete all elements from the given array and frees it and the array.
 * @param list the list to destroy
 * @param destroy_data a function pointer for freeing a given element
 * @return always true
 *
 * NULL is not acceptable for the list, but acceptable for destroy_data, in
 * which case your memory will not be freed at all if it needed to be. If you
 * have simply allocated memory for your elements using (sharp_)malloc(),
 * you will want to pass the function pointer to free() here.
 */
bool sharp_dynamicarray_destroy(sharp_dynamicarray **list, 
    void (*destroy_data)(void *data));

/**
 * Tells you whether or not the array is currently empty.
 * @param list the array whose length to determine
 * @return true if the array is empty, false otherwise.
 */
bool sharp_dynamicarray_isempty(sharp_dynamicarray *list);

#endif /* _SHARP_DYNAMICARRAY_H */
